#include "Sys.h"
#include "SysEncryption.h"
#include "Remote.h"
#include "Wireless.h"
#include "UserMain.h"
#include "Manufacture.h"

#define SYS_DEVICE_MODEL "ZBD1"
#define SYS_SOFT_VERSION "0.0.1"
#define SYS_PWM_FREQUENCY 100000 // 10us
#define SYS_FLASH_INFO_FLAG 0x4577

#define SYS_THROTTLE_MIN_VAL 1000
#define SYS_THROTTLE_MAX_VAL 4000
#define SYS_THROTTLE_STEP_VAL 100

typedef enum
{
    SYS_THROTTLE_OPT_NONE = 0,
    SYS_THROTTLE_OPT_INC,
    SYS_THROTTLE_OPT_DEC
} SysThrottleOperate_t;

static uint16_t g_valveFrequency = 100;
//static uint16_t g_throttle = 0;

uint32_t SysWirelessAddressGet(void)
{
    // return SysGetManufactoryInfo()->wirelessAddress;
    return 0x01000007; //FIXME: test
}

SysDeviceType_t SysDeviceType(void)
{
    return SYS_DEVICE_TYPE_ZBD;
}

void SysSetValveFrequency(uint16_t hz)
{
    g_valveFrequency = hz;
}

uint16_t SysGetPWMCount(void)
{
    return (SYS_PWM_FREQUENCY / g_valveFrequency);
}

void SysThrottleReset(void)
{
    HalGPIOSetLevel(HAL_PIN_OUT_RPM_SWITCH, 0);
    HalDACSetValue(HAL_DAC_CH_RPM, 0);
}

void SysThrottleSet(uint16_t val)
{
    HalGPIOSetLevel(HAL_PIN_OUT_RPM_SWITCH, val != 0);
    HalDACSetValue(HAL_DAC_CH_RPM, (uint16_t)(val * 0.7475)); // 0.7475 = 4096 / 5480mv
}

#define SYS_AUTH_DATA_BUFF_SIZE (24 + 96)
static const char *SECRET_KEY = "l8WohL5Niy3iKo1sYQJWU6Wa69JstUom6lFiYhkyfkMtaAFsqhCNAuZRIrpTpoQMzdAeOSI3qzZdvIdYAWS62EKA9E2whhvh";
static bool g_isAuthorized = false;

bool SysAuthCodeCheck(const uint8_t *authcode)
{
    unsigned char i = 0;
    char buff[SYS_AUTH_DATA_BUFF_SIZE + 1];
    unsigned char enccode[16];
    uint8_t uuid[HAL_UUID_LEN];

    memset(buff, 0, sizeof(buff));
    HalGetUUID(uuid);
    for (i = 0; i < HAL_UUID_LEN; i++)
    {
        sprintf(&buff[i * 2], "%02x", uuid[i]);
    }
    strcat(buff, SECRET_KEY);

    Encryption_CTX ctx;
    SysEncryptionInit(&ctx);
    SysEncryptionUpdate(&ctx, (uint8_t *)buff, SYS_AUTH_DATA_BUFF_SIZE);
    SysEncryptionFinal(&ctx, enccode);

    if (memcmp((void *)authcode, enccode, sizeof(enccode)) == 0)
    {
        return true;
    }
    return false;
}

bool SysIsAuthorized(void)
{
    // return g_isAuthorized;
    return true; //FIXME: test
}

SysManufactoryInfo_t *SysGetManufactoryInfo(void)
{
    return (SysManufactoryInfo_t *)HAL_FLASH_MANUFACTORY_INFO_ADDR;
}

void SysManufactoryInfoWrite(uint32_t wladdress, uint8_t *authcode)
{
    SysManufactoryInfo_t ids;

    HalFlashRead(HAL_FLASH_MANUFACTORY_INFO_ADDR, (uint8_t *)&ids, sizeof(SysManufactoryInfo_t));
    if (wladdress != SYS_WIRELESS_BRAODCAST_ADDRESS)
    {
        ids.wirelessAddress = wladdress;
    }

    if (authcode != NULL)
    {
        memcpy(ids.authCode, authcode, HAL_AUTH_KEY_LEN);
    }
    HalFlashErase(HAL_FLASH_MANUFACTORY_INFO_ADDR);
    HalFlashWrite(HAL_FLASH_MANUFACTORY_INFO_ADDR, (uint8_t *)&ids, sizeof(SysManufactoryInfo_t));
}

const char *SysVersion(void)
{
    return SYS_SOFT_VERSION;
}

const char *SysDeviceModel(void)
{
    return SYS_DEVICE_MODEL;
}

static void printLog(void)
{
    uint8_t uuid[16];

    sysPrint("\n\n\n");
    sysPrint("**********************************\n");
    sysPrint("Firmware version: %s\n", SYS_SOFT_VERSION);
    HalGetUUID(uuid);
    sysPrint("UUID: ");
    for (uint8_t i = 0; i < HAL_UUID_LEN; i++)
    {
        sysPrint("%02x", uuid[i]);
    }
    sysPrint("\n");
    sysPrint("%s\n", g_isAuthorized ? "Authorized" : "Unauthorize");
    sysPrint("Build time: %s %s\n", __DATE__, __TIME__);
    sysPrint("**********************************\n");
}

static void lowlevelInit(void)
{
    SysManufactoryInfo_t *mfInfo = SysGetManufactoryInfo();
    g_isAuthorized = SysAuthCodeCheck(mfInfo->authCode);
    printLog();
}

void SysInitialize(void)
{
    HalInitialize();
    lowlevelInit();
    SysDelayProcessInit();
    UserMainInitialize();
    MFInitialize();
}

void SysPoll(void)
{
    HalPoll();
    SysDelayProcessPoll();
    MFPoll();
    if (!MFIsStartup())
    {
        UserMainPoll();
    }
}
